﻿/**
 * The main entry point for our game.
 * This class contains the main game loop which tells the right parts of the game to run.
 **/

using System.Windows.Forms;
using AgateLib;
using AgateLib.DisplayLib;
using AgateLib.Geometry;
using AiAsteriods.Game.State;
using AiAsteriods.Game.Tools;

namespace AiAsteriods.Game {
  class GameStart {
    private const string configFile = "config.xml";
    private int currentState = 0;
    private double avgDelta = 10;
    private ResourceManager rm;
    private GameStateAbstract[] gameStates;

    public int ScreenWidth { get; set; }
    public int ScreenHeight { get; set; }
    public GameStateAbstract CurrentState { get { return gameStates[currentState]; } }
    public ResourceManager RM { get { return rm; } }
    public double GetDelta { get { return avgDelta; } }
    public Config Config { get; set; }

    public GameStart() {
      Global.Init();
      Global.GameStart = this;

      ScreenHeight = (int)(Screen.PrimaryScreen.Bounds.Height / 1.2f);
      ScreenWidth = (int)(Screen.PrimaryScreen.Bounds.Width / 1.2f);

      Config config = Serializer<Config>.Deserialize(configFile);
      //double cw = Global.GameStart.ScreenWidth / (double)config.GridRes;
      //config.RCSize = (int)Math.Ceiling(config.RCSize / cw);
      //config.RLRSize = (int)Math.Ceiling(config.RLRSize / cw);
      Config = config;

      using (AgateSetup setup = new AgateSetup("")) {
        // initialize AgateLib.
        setup.InitializeAll();

        // if something bad happened, bail out.
        if (setup.WasCanceled)
          return;

        // Create a window with resolution stated before
        DisplayWindow wind = DisplayWindow.CreateWindowed("AI ASTERIODS", ScreenWidth, ScreenHeight);

        //wind.SetFullScreen();
        Display.VSync = false;

        // to give the player something nice to look at and to tell them that we are working give them a loading screen
        Display.BeginFrame();
        LoadingScreen();
        Display.EndFrame();
        Core.KeepAlive();

        // start the resource manager and give it the zip file that our resources are placed in
        rm = new ResourceManager(10, "data.zip");

        // make an array of our different gamestates.
        // each gamestate contains a specific part of the game, like the menu, and the game itself.
        gameStates = new AiAsteriods.Game.State.GameStateAbstract[3];
        gameStates[0] = new MenuState(rm, this); // 0 = menu state
        gameStates[1] = new GameState(rm, this);

        // init all our states, run all the init methods in the gameStates so we can do our preloadin
        foreach (GameStateAbstract gs in gameStates) {
          if (gs != null) {
            gs.InitState();
          }
        }

        // enter our current state, the menu state currentState = 0 as default.
        SwitchStates(currentState);

        // variables used to figure our out delta.
        // delta is the time that has passed between this frame and the previous frame
        // using this we can figure out how far we need to move our game objects.
        int remainder = 0;
        int delta = 0;
        int step = 0;

        while (Display.CurrentWindow.IsClosed == false) {
          // these are drawing methods that are specific to AgateLib, the graphics library we are using.
          Display.BeginFrame();

          // set background color to black
          Display.Clear(Color.Black);

          // get this frames delta time.
          delta = (int)Display.DeltaTime;

          // make an average over the last 100 frames so we know how many fps we have.
          avgDelta = ((avgDelta / 100d) * 99d) + ((double)delta / 100d);

          // how many multiples of 10 fit into this delta.
          // if we have a delta of 24 then we want to do 2 updates of 10 milliseconds and 1 update of 4 ms.
          // this is because we dont want to take too big steps at once. Things like collision detection need to be run at close intervals so 
          // objects dont pass through eachother. 
          remainder = delta % 10;
          step = delta / 10;

          for (int i = 0; i < step; i++) {
            gameStates[currentState].UpdateState(10);
          }
          if (remainder != 0) {
            gameStates[currentState].UpdateState(remainder);
          }

          // once all the updating is done we draw the current state of the gamestate.
          gameStates[currentState].AddScoreForTime(delta);
          gameStates[currentState].DrawState();

          // do the AgateLib specific drawing things.
          Display.EndFrame();
          Core.KeepAlive();
        }
      }
    }

    /*
     * Draw the text Loading on the screen 
     */
    private void LoadingScreen() {
      Display.Clear(Color.White);
      FontSurface font = new AgateLib.DisplayLib.FontSurface("Arial", 15);
      font.Color = Color.Black;
      for (int m = 0; m < 40; m++) {
        font.DrawText(ScreenWidth / 2 - 40, ScreenHeight / 2 - 10, "Loading...");
      }
    }

    /*
     * Switch to another state, tell the current state we are leaving it 
     * and tell the state we are going into that we are using it.. 
     */
    public void SwitchStates(int i) {
      if (gameStates[currentState] != null)
        gameStates[currentState].LeaveState();

      gameStates[i].EnterState(gameStates[currentState]);
      currentState = i;
    }

    /*
     * Reset the "game" gameState, i.e. the user wants a new game.
     */
    public void ResetGame() {
      LoadingScreen();
      Display.EndFrame();
      Core.KeepAlive();

      gameStates[1].LeaveState();

      gameStates[1] = new GameState(rm, this);
      gameStates[1].InitState();
      Display.BeginFrame();
    }
  }
}
